#include <stdio.h>
#include "hd_oled.h"
#include "delay.h"
#include "main.h"
#include "pd_h_flash.h"
#include "pd_h_usart.h"

void SystemClock_Config(void);

int main(void) {
    SystemClock_Config();

    PD_H_USART1_Init();

    HD_OLED_Init(OLED_SIZE_16, OLED_MODE_POSITIVE);

    /* Flash write */
    uint32_t writeAddr = 0x0801FFE0;
    // 解锁
    PD_H_FLASH_Unlock();
    // 擦除
    uint32_t PageError;
    LL_FLASH_EraseInitTypeDef FLASH_EraseInitStruct;
    FLASH_EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
    FLASH_EraseInitStruct.Banks = FLASH_BANK_1;
    FLASH_EraseInitStruct.Page = (writeAddr - FLASH_BASE) / FLASH_PAGE_SIZE;
    FLASH_EraseInitStruct.NbPages = 1;
    PD_H_FLASH_Erase(&FLASH_EraseInitStruct, &PageError);
    // 写入
    PD_H_FLASH_Program(FLASH_TYPEPROGRAM_DOUBLEWORD, writeAddr, 0x12345678);
    // 锁定
    PD_H_FLASH_Lock();

    /* Flash read */
    HD_OLED_ShowString(0, 0, "FLASH");
    HD_OLED_ShowString(0, 16, "PACKAGE:");
    HD_OLED_ShowBinNum(64, 16, PD_H_FLASH_ReadHalfWord(PACKAGE_BASE), 5);

    HD_OLED_ShowString(0, 32, "SIZE:");
    HD_OLED_ShowNum(40, 32, PD_H_FLASH_ReadHalfWord(FLASHSIZE_BASE), 5);

    HD_OLED_ShowString(0, 48, "UID:");
    uint64_t uid;
    uid = PD_H_FLASH_ReadWord(UID_BASE);
    uid <<= 32;
    uid |= PD_H_FLASH_ReadWord(UID_BASE + 4);
    HD_OLED_ShowHexNum(56, 48, uid, 8);
    uid = PD_H_FLASH_ReadWord(UID_BASE + 8);
    HD_OLED_ShowHexNum(32, 48, (uint32_t) uid, 4);

    while (1) {}

}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void) {
    LL_FLASH_SetLatency(LL_FLASH_LATENCY_4);
    while (LL_FLASH_GetLatency() != LL_FLASH_LATENCY_4) {
    }
    LL_PWR_EnableRange1BoostMode();
    LL_RCC_HSE_Enable();
    /* Wait till HSE is ready */
    while (LL_RCC_HSE_IsReady() != 1) {
    }

    LL_RCC_PLL_ConfigDomain_SYS(LL_RCC_PLLSOURCE_HSE, LL_RCC_PLLM_DIV_6, 85, LL_RCC_PLLR_DIV_2);
    LL_RCC_PLL_EnableDomain_SYS();
    LL_RCC_PLL_Enable();
    /* Wait till PLL is ready */
    while (LL_RCC_PLL_IsReady() != 1) {
    }

    LL_RCC_SetSysClkSource(LL_RCC_SYS_CLKSOURCE_PLL);
    LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_2);
    /* Wait till System clock is ready */
    while (LL_RCC_GetSysClkSource() != LL_RCC_SYS_CLKSOURCE_STATUS_PLL) {
    }

    /* Insure 1?s transition state at intermediate medium speed clock based on DWT */
    CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
    DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
    DWT->CYCCNT = 0;
    while (DWT->CYCCNT < 100);
    /* Set AHB prescaler*/
    LL_RCC_SetAHBPrescaler(LL_RCC_SYSCLK_DIV_1);
    LL_RCC_SetAPB1Prescaler(LL_RCC_APB1_DIV_1);
    LL_RCC_SetAPB2Prescaler(LL_RCC_APB2_DIV_1);

    LL_Init1msTick(170000000);

    LL_SetSystemCoreClock(170000000);
}


#ifdef  USE_FULL_ASSERT

/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line) {
    /* USER CODE BEGIN 6 */
    /* User can add his own implementation to report the file name and line number,
       ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
    /* USER CODE END 6 */
}

#endif /* USE_FULL_ASSERT */